﻿using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.DependencyInjection.Extensions;
using Newtonsoft.Json;
using Newtonsoft.Json.Serialization;
using PmSoft.Core.Domain;
using PmSoft.Core.FileStorage;
using PmSoft.Web.Abstractions.Attachment;
using PmSoft.Web.Abstractions.Auditing;
using PmSoft.Web.Abstractions.Captcha;
using PmSoft.Web.Abstractions.ErrorCode;
using PmSoft.Web.Abstractions.Filters;
using PmSoft.Web.Abstractions.Middlewares;
using PmSoft.Web.Abstractions.Notifications;
using PmSoft.Web.Abstractions.RealTime;
using PmSoft.Web.Abstractions.Services;
using PmSoft.Web.Abstractions.Settings;
using PmSoft.Web.Abstractions.SignalR;
using PmSoft.Web.Abstractions.SignalR.Hubs;
using PmSoft.Web.Abstractions.SignalR.Notifications;
using System.IO;

namespace PmSoft.Web.Abstractions;

public static class ServiceCollectionExtensions
{
	/// <summary>
	/// 添加 Web 核心服务到依赖注入容器
	/// </summary>
	/// <param name="services">服务集合</param>
	/// <param name="configuration">配置对象</param>
	/// <returns>服务集合</returns>
	public static IServiceCollection AddWebCore(this IServiceCollection services, IConfiguration configuration)
	{
		// 初始化错误码管理器
		ErrorCodeManager.Initialize(Path.Combine(Environment.CurrentDirectory, "Config", "error-codes.json"));

		// 配置路由选项，设置 URL 为小写
		services.AddRouting(options =>
		{
			options.LowercaseUrls = true;
		});

		// 注册 HttpContext 访问器，用于在服务中访问当前请求的 HttpContext
		services.AddHttpContextAccessor();

		// 配置控制器服务
		services.AddControllers(options =>
		{
			// 添加全局异常过滤器
			options.Filters.Add<GlobalExceptionFilter>();

			// 添加全局模型验证过滤器
			options.Filters.Add<GlobalModelValidationFilter>();

			// 添加全局 API 响应过滤器
			options.Filters.Add<GlobalApiResponseFilter>();
		})
		// 配置 Newtonsoft.Json 作为 JSON 序列化器
		.AddNewtonsoftJson(options =>
		{
			// 忽略空值
			options.SerializerSettings.NullValueHandling = NullValueHandling.Ignore;

			// 配置 JSON 命名策略为驼峰命名法
			options.SerializerSettings.ContractResolver = new JsonContractResolver()
			{
				NamingStrategy = new CamelCaseNamingStrategy()
			};

			// 添加自定义的日期时间转换器
			options.SerializerSettings.Converters.Add(new DateTimeJsonConverter());

			// 添加自定义的日期时间（可为空）转换器
			options.SerializerSettings.Converters.Add(new DateTimeNullJsonConverter());
		})
		// 配置 API 行为选项
		.ConfigureApiBehaviorOptions(options =>
		{
			// 禁用默认的模型验证过滤器
			options.SuppressModelStateInvalidFilter = true;

			// 自定义模型验证失败的响应
			options.InvalidModelStateResponseFactory = context =>
			{
				// 提取模型验证错误信息
				var errors = context.ModelState
					.Where(m => m.Value?.Errors.Count > 0)
					.Select(m => new
					{
						Field = m.Key, // 字段名称
						Error = m.Value?.Errors.Select(e => e.ErrorMessage).FirstOrDefault() // 错误信息
					});

				// 返回自定义的 BadRequest 响应
				return new BadRequestObjectResult(new ApiResult
				{
					Msg = "输入验证失败",
					Success = false,
					Code = "VALIDATION_ERROR",
					Data = errors
				});
			};
		});

		// 注册客户端信息提供者
		services.AddScoped<IClientInfoProvider, HttpContextClientInfoProvider>();
		//注册限流中间件
		services.AddScoped<RateLimitMiddleware>();

		return services;
	}

	/// <summary>
	/// 添加通知相关服务到依赖注入容器
	/// </summary>
	/// <param name="services">服务集合</param>
	/// <returns>服务集合</returns>
	public static IServiceCollection AddNotification(this IServiceCollection services)
	{
		// 注册在线客户端信息提供者
		services.AddScoped<IOnlineClientInfoProvider, OnlineClientInfoProvider>();

		// 注册在线客户端管理器
		services.AddSingleton<IOnlineClientManager, OnlineClientManager>();

		// 注册在线客户端存储（内存实现）
		services.AddSingleton<IOnlineClientStore, InMemoryOnlineClientStore>();

		// 注册实时通知器（SignalR 实现）
		services.AddScoped<IRealTimeNotifier, SignalRRealTimeNotifier>();

		// 添加 SignalR 服务
		services.AddSignalR();

		return services;
	}

	/// <summary>
	/// 使用通知相关中间件
	/// </summary>
	/// <param name="builder">应用程序构建器</param>
	/// <param name="chatHubPath">SignalR Hub 的路径，默认为 "/chatHub"</param>
	/// <returns>应用程序构建器</returns>
	public static IApplicationBuilder UseNotification(this IApplicationBuilder builder,
		string chatHubPath)
	{
		NotificationSettings.ChatHubPath = chatHubPath;

		// 配置终结点路由
		builder.UseEndpoints(endpoints =>
		{
			// 映射 CommonHub 到 "/chatHub" 路由
			endpoints.MapHub<CommonHub>(NotificationSettings.ChatHubPath);
		});

		return builder;
	}

	/// <summary>
	/// 添加上传相关服务到依赖注入容器
	/// </summary>
	/// <param name="services"></param>
	/// <param name="configuration"></param>
	/// <returns></returns>
	public static IServiceCollection AddFileUploadService(this IServiceCollection services, IConfiguration configuration)
	{
		services.AddStorageServices(configuration);
		services.TryAddSingleton<IFileUploadService, DefaultFileUploadService>();
		return services;
	}

	/// <summary>
	/// 添加附件管理器相关服务到依赖注入容器
	/// </summary>
	/// <param name="services"></param>
	/// <param name="configuration"></param>
	/// <returns></returns>
	public static IServiceCollection AddAttachmentManager(this IServiceCollection services, IConfiguration configuration)
	{
		services.AddFileUploadService(configuration);

		((ConfigurationManager)configuration)
			.AddJsonFile(Path.Combine(Environment.CurrentDirectory, "Config", "attachment.json"), optional: false, reloadOnChange: true);

		var tenantConfigs = configuration.GetSection("TenantConfig").Get<List<TenantStorageConfig>>() ?? new();

		services.AddSingleton(tenantConfigs);
		services.TryAddScoped<AttachmentManagerService>();
		return services;
	}

	/// <summary>
	/// 添加点选文字验证码相关服务到依赖注入容器
	/// </summary>
	/// <param name="services"></param>
	/// <param name="configuration"></param>
	/// <returns></returns>
	public static IServiceCollection AddCaptcha(this IServiceCollection services, IConfiguration configuration)
	{
		((ConfigurationManager)configuration)
			.AddJsonFile(Path.Combine(Environment.CurrentDirectory, "Config", "captcha.json"), optional: false, reloadOnChange: true);
		//services.Configure<ClickCaptchaOptions>(configuration.GetSection("ClickCaptcha"));
		services.TryAddSingleton<ClickCaptchaService>();
		// 配置服务
		services.Configure<CaptchaOptions>(
			configuration.GetSection("ImageCaptcha"));
		services.TryAddSingleton<CaptchaService>();
		return services;
	}
}